/* Field.cpp
Michael Zahniser, 2008

Function definitions for the Field class.
*/

#include "Field.h"

#include <ncurses.h>



Field::Field(const string &label)
	: label(label), fullLabel(label + ": "), isValid(false)
{
}



// Draw this field in the given row.
void Field::Draw(int y, int x) const
{
	mvaddstr(y, x, fullLabel.c_str());
	int atrributes = A_BOLD | (A_REVERSE * !isValid);
	attron(atrributes);
	addstr(value.c_str());
	attroff(atrributes);
}



// Process the given key press.
bool Field::HandleKey(int key)
{
	if(key == KEY_BACKSPACE || key == 127)
	{
		if(!value.empty())
			value.erase(value.end() - 1, value.end());
	}
	else if(key == '\r' || key == '\n')
	{
		if(isValid)
		{
			if(value.empty())
				value = defaultValue;
			onEnter(value);
			return true;
		}
	}
	else if(key == '\t')
		onComplete(value);
	else if(key < 128)
		value += static_cast<char>(key);
	
	Validate();
		
	return false;
}



// Get the number of characters used to display this field's label and contents.
int Field::Width() const
{
	return static_cast<int>(fullLabel.length() + value.length());
}



// Get the label of this field.
const string &Field::Label()
{
	return label;
}



// Get the default value of this field.
const string &Field::DefaultValue()
{
	return defaultValue;
}



// Get the current value of this field.
const string &Field::Value()
{
	return value;
}



// This function is called whenever the text of a field changes, to check whether the
// current contents of the field are valid. The validation function can either return
// false if a field is invalid, or edit the field to make it valid and return true.
Field &Field::OnValidate(Callback callback, void *data)
{
	onValidate.Set(callback, data);
	
	Validate();

	return *this;
}



// This function is called whenever the user presses <tab>, to perform tab-completion.
Field &Field::OnComplete(Callback callback, void *data)
{
	onComplete.Set(callback, data);

	return *this;
}



// This function is called when the user presses <enter>.
Field &Field::OnEnter(Callback callback, void *data)
{
	onEnter.Set(callback, data);

	return *this;
}



// Set the default value of this field.
// If a default is set, it is used if the user presses <enter> on an empty field.
Field &Field::SetDefault(const string &defaultValue)
{
	this->defaultValue = defaultValue;
	
	// Update the full label text.
	fullLabel = label;
	if(!defaultValue.empty())
		fullLabel += " [" + defaultValue + "]";
	fullLabel += ": ";
	
	Validate();

	return *this;
}
	


// Validate the current text contents.
void Field::Validate()
{
    isValid = (value.empty() & !defaultValue.empty()) || onValidate(value);
}
